import { ButtonProps } from 'antd';
import React, { Fragment, useCallback, useMemo } from 'react';
import { useContextSelector } from 'use-context-selector';

import MultipleRowSelect from '@/components/MySelect/MultipleRowSelect';
import AvatarDisplay from '@/components/work-modal/components/AvatarDisplay';
import { t } from '@/locales/i18n';
import { AppContext } from '@/pages/app/detail/context';
import {
  FlowNodeTypeEnum,
  NodeOutputKeyEnum,
  VARIABLE_NODE_ID,
  WorkflowIOValueTypeEnum,
} from '@/types/workflow/constant';
import { ReferenceValueProps } from '@/types/workflow/io';
import { computedNodeInputReference } from '@/utils/workflow/utils';

import { WorkflowContext } from '../../../../../context';

import type { RenderInputProps } from '../type';

type SelectProps = {
  value?: ReferenceValueProps;
  placeholder?: string;
  list: {
    label: string | React.ReactNode;
    value: string;
    children: {
      label: string;
      value: string;
      valueType?: WorkflowIOValueTypeEnum;
    }[];
  }[];
  onSelect: (val: ReferenceValueProps) => void;
  popDirection?: 'top' | 'bottom';
  styles?: ButtonProps;
};

const Reference = ({ item, nodeId }: RenderInputProps) => {
  const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
  const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);

  const onSelect = useCallback(
    (e: ReferenceValueProps) => {
      const workflowStartNode = nodeList.find(
        (node) => node.flowNodeType === FlowNodeTypeEnum.workflowStart,
      );
      if (e[0] === workflowStartNode?.id && e[1] !== NodeOutputKeyEnum.userChatInput) {
        onChangeNode({
          nodeId,
          type: 'updateInput',
          key: item.key,
          value: {
            ...item,
            value: [VARIABLE_NODE_ID, e[1]],
          },
        });
      } else {
        onChangeNode({
          nodeId,
          type: 'updateInput',
          key: item.key,
          value: {
            ...item,
            value: e,
          },
        });
      }
    },
    [item, nodeId, nodeList, onChangeNode],
  );

  const { referenceList, formatValue } = useReference({
    nodeId,
    valueType: item.valueType,
    value: item.value,
  });

  const popDirection = useMemo(() => {
    const node = nodeList.find((node) => node.nodeId === nodeId);
    if (!node) return 'bottom';
    return node.flowNodeType === FlowNodeTypeEnum.loop ? 'top' : 'bottom';
  }, [nodeId, nodeList]);

  return (
    <ReferSelector
      placeholder={t((item.referencePlaceholder as any) || 'select_reference_variable')}
      list={referenceList}
      value={formatValue}
      onSelect={onSelect}
      popDirection={popDirection}
    />
  );
};

export default React.memo(Reference);

export const useReference = ({
  nodeId,
  valueType = WorkflowIOValueTypeEnum.any,
  value,
}: {
  nodeId: string;
  valueType?: WorkflowIOValueTypeEnum;
  value?: any;
}) => {
  const { appDetail } = useContextSelector(AppContext, (v) => v);
  const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
  const edges = useContextSelector(WorkflowContext, (v) => v.edges);

  const referenceList = useMemo(() => {
    const sourceNodes = computedNodeInputReference({
      nodeId,
      nodes: nodeList,
      edges,
      chatConfig: appDetail.chatConfig,
      t,
    });

    if (!sourceNodes) return [];

    // 转换为 select 的数据结构
    const list: SelectProps['list'] = sourceNodes
      .map((node) => {
        return {
          label: (
            <div className="flex items-center">
              <AvatarDisplay
                src={`${node.avatar!}`}
                className="h-[18px] max-h-[18px] w-[18px] max-w-[18px]"
                size={18}
              />
              <div className="ml-1">{t(node.name as any)}</div>
            </div>
          ),
          value: node.nodeId,
          children: node.outputs
            .filter(
              (output) =>
                valueType === WorkflowIOValueTypeEnum.any ||
                output.valueType === WorkflowIOValueTypeEnum.any ||
                output.valueType === valueType ||
                // When valueType is arrayAny, return all array type outputs
                (valueType === WorkflowIOValueTypeEnum.arrayAny &&
                  output.valueType?.includes('array')),
            )
            .filter((output) => output.id !== NodeOutputKeyEnum.addOutputParam)
            .map((output) => {
              return {
                label: t((output.label as any) || ''),
                value: output.id,
                valueType: output.valueType,
              };
            }),
        };
      })
      .filter((item) => item.children.length > 0);

    return list;
  }, [appDetail.chatConfig, edges, nodeId, nodeList, valueType]);

  const formatValue = useMemo(() => {
    if (
      Array.isArray(value) &&
      value.length === 2 &&
      typeof value[0] === 'string' &&
      typeof value[1] === 'string'
    ) {
      return value as ReferenceValueProps;
    }
    return undefined;
  }, [value]);

  return {
    referenceList,
    formatValue,
  };
};

const capitalizeFirstLetter = (str?: string) => {
  if (!str) return '';
  return str.charAt(0).toUpperCase() + str.slice(1);
};

export const ReferSelector = ({
  placeholder,
  value,
  list = [],
  onSelect,
  popDirection,
}: SelectProps) => {
  const selectItemLabel = useMemo(() => {
    if (!value) {
      return undefined;
    }
    const firstColumn = list.find((item) => item.value === value[0]);
    if (!firstColumn) {
      return undefined;
    }
    const secondColumn = firstColumn.children.find((item) => item.value === value[1]);
    if (!secondColumn) {
      return undefined;
    }
    return [firstColumn, secondColumn] as const;
  }, [list, value]);

  const Render = useMemo(() => {
    return (
      <MultipleRowSelect
        label={
          selectItemLabel ? (
            <div className="flex w-fit items-center rounded-md bg-white px-2 py-1 text-xs">
              {selectItemLabel?.map((item, index) => (
                <div key={index} className="flex flex-1 text-nowrap">
                  {typeof item === 'string' ? item : item?.label || ''}
                  <span className="mx-1">{item && index === 0 ? '/' : ''}</span>
                </div>
              ))}
            </div>
          ) : (
            <div className="text-xs">{placeholder}</div>
          )
        }
        value={value as any[]}
        list={list}
        onSelect={(e) => {
          onSelect(e as ReferenceValueProps);
        }}
        popDirection={popDirection}
      />
    );
  }, [list, onSelect, placeholder, popDirection, selectItemLabel, value]);

  return Render;
};

export const ReferenceLabel = ({
  nodeId,
  variable,
}: {
  nodeId: string;
  variable?: ReferenceValueProps;
}) => {
  const { referenceList, formatValue } = useReference({
    nodeId,
    valueType: WorkflowIOValueTypeEnum.any,
    value: variable,
  });

  const selectItemLabel = useMemo(() => {
    if (!formatValue) {
      return undefined;
    }
    const firstColumn = referenceList.find((item) => item.value === formatValue[0]);
    if (!firstColumn) {
      return undefined;
    }
    const secondColumn = firstColumn.children.find((item) => item.value === formatValue[1]);
    if (!secondColumn) {
      return undefined;
    }
    return [firstColumn.label, secondColumn.label] as const;
  }, [referenceList, formatValue]);

  return (
    <div className="flex">
      {selectItemLabel?.map((item, index) => (
        <Fragment key={index}>
          {index > 0 && <span className="mx-1">/</span>}
          <div className="flex-1 text-nowrap">{item}</div>
        </Fragment>
      ))}
    </div>
  );
};
